package com.sinosoft.system.primary.action;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.sinosoft.system.primary.biz.SysRoleBiz;
import com.sinosoft.system.primary.biz.SysTokenBiz;
import com.sinosoft.system.primary.biz.SysUserBiz;
import com.sinosoft.system.primary.entity.SysCredentials;
import com.sinosoft.system.primary.entity.SysRole;
import com.sinosoft.system.primary.entity.SysToken;
import com.sinosoft.system.primary.entity.SysUser;
import com.sinosoft.system.primary.realm.UUIDGenerator;
import com.sinosoft.system.util.Result;
import com.sinosoft.system.util.jsonutil.JsonUtil;
import com.sinosoft.system.util.jwt.JoseJwt;
import com.sinosoft.system.util.jwt.JwtUtil;

/**
 * 
 * @author Administrator
 *
 */

@RestController  
@RequestMapping("SysUser") 
public class LoginAction {
	private Logger log = Logger.getLogger(this.getClass());
	
	@Autowired
	private SysUserBiz sysUserBiz;
	@Autowired
	private SysRoleBiz sysRoleBiz;
	@Autowired
	private SysTokenBiz sysTokenBiz;
	
	
	/** 
     * 用户登录 
     */  
    @RequestMapping(value="/login", method=RequestMethod.POST)  
    @CrossOrigin(methods={RequestMethod.POST})
    public ResponseEntity<List> login(HttpServletRequest request){
    	String username = request.getParameter("username");  
        String password = request.getParameter("password");
        String ipaddr = request.getRemoteAddr();
        log.info(username+"登陆系统");
        
        List<String> queryKeys = new ArrayList<String>();
        queryKeys.add("username");
        queryKeys.add("password");

        List<Object> queryValues = new ArrayList<Object>(); 
        queryValues.add(username);
        queryValues.add(password);
        SysUser sysUser = sysUserBiz.selectSysUser(queryKeys, queryValues);
        List<Object> retList = new ArrayList<Object>();
        if(sysUser!=null){
        	
        	List<SysRole> sysRoles = sysRoleBiz.selectByUserId(sysUser.getId());
        	String strRoles = "";
        	String StrRoleIds = "";
        	if(sysRoles!=null && !sysRoles.isEmpty()){        		
        		for(int i=0;i<sysRoles.size();i++){
        			strRoles += sysRoles.get(i).getRoleName()+",";
        			StrRoleIds += sysRoles.get(i).getId()+",";
        		}
        		strRoles = strRoles.substring(0, strRoles.lastIndexOf(","));
        		StrRoleIds = StrRoleIds.substring(0,StrRoleIds.lastIndexOf(","));
        	}
        	
        	String issuer = "qianniukeji";//发布者牵牛科技
        	Long TTLMillis = 180L*24L*60L*60L*1000L;//保存180天
        	long nowMillis = System.currentTimeMillis();
        	long expMillis = nowMillis + TTLMillis; 
        	Date now = new Date();
        	String jwtString = Jwts.builder()
        			.setHeaderParam("typ", "JWT")
        			.setSubject(username)
        			.claim("roleIds",StrRoleIds)
        			.claim("roles",strRoles)
        			.setIssuer(issuer)
        			.setIssuedAt(now)
        			.setExpiration(new Date(expMillis))
        			.setNotBefore(now)
        			.signWith(SignatureAlgorithm.HS256, "secretkeyshangxp").compact();
        	SysToken sysToken = new SysToken(sysUser.getId(),sysUser.getUsername(),strRoles,issuer,jwtString,String.valueOf(System.currentTimeMillis()),String.valueOf(TTLMillis),ipaddr);
        	sysTokenBiz.insertSysToken(sysToken);//token入库
        	retList.add(new Result("OK",jwtString));  //返回结果添加token信息	
        	retList.add(sysUser);//返回结果添加用户信息
        	retList.add(sysRoles); //返回结果添加角色信息
        	log.info(username+"登陆系统成功,token:"+jwtString);
        	return new ResponseEntity<List>(retList, HttpStatus.OK);
        }else{
        	retList.add(new Result("error","用户名或密码错误，请重新输入！"));
        	log.info(username+"登陆系统失败");
        	return new ResponseEntity<List>(retList, HttpStatus.OK);
        }
    }
    
    /** 
     * 用户登录 
     */  
    @RequestMapping(value="/shiroLogin", method=RequestMethod.POST)  
    @CrossOrigin(methods={RequestMethod.POST})
    public ResponseEntity<List> shiroLogin(HttpServletRequest request){
    	String username = request.getParameter("username");  
        String password = request.getParameter("password");  
 
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);  
        token.setRememberMe(true);  
        log.debug("为了验证登录用户而封装的token为" + ReflectionToStringBuilder.toString(token, ToStringStyle.MULTI_LINE_STYLE));  
        //获取当前的Subject  
        Subject currentUser = SecurityUtils.getSubject();  
        try {  
            //在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查  
            //每个Realm都能在必要时对提交的AuthenticationTokens作出反应  
            //所以这一步在调用login(token)方法时,它会走到MyRealm.doGetAuthenticationInfo()方法中,具体验证方式详见此方法  
            log.debug("对用户[" + username + "]进行登录验证..验证开始");  
            currentUser.login(token); 
            log.debug("对用户[" + username + "]进行登录验证..验证通过");

            //验证码通过
//            return new ResponseEntity<Result>(new Result("OK",jwtToken), HttpStatus.OK);  
        }catch(UnknownAccountException uae){  
            log.debug("对用户[" + username + "]进行登录验证..验证未通过,未知账户");
            //request.setAttribute("message_login", "未知账户");
//            return new ResponseEntity<Result>(new Result("2","未知账户"), HttpStatus.OK); 
        }catch(IncorrectCredentialsException ice){  
            log.debug("对用户[" + username + "]进行登录验证..验证未通过,错误的凭证");  
            //request.setAttribute("message_login", "密码不正确"); 
 //           return new ResponseEntity<Result>(new Result("3","密码不正确"), HttpStatus.OK);
        }catch(LockedAccountException lae){  
            log.debug("对用户[" + username + "]进行登录验证..验证未通过,账户已锁定");  
            //request.setAttribute("message_login", "账户已锁定"); 
//            return new ResponseEntity<Result>(new Result("4","账户已锁定"), HttpStatus.OK);
        }catch(ExcessiveAttemptsException eae){  
            log.debug("对用户[" + username + "]进行登录验证..验证未通过,错误次数过多");  
            //request.setAttribute("message_login", "用户名或密码错误次数过多"); 
//            return new ResponseEntity<Result>(new Result("5","用户名或密码错误次数过多"), HttpStatus.OK);
        }catch(AuthenticationException ae){  
            //通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景  
            log.debug("对用户[" + username + "]进行登录验证..验证未通过,堆栈轨迹如下");  
            ae.printStackTrace();  
            //request.setAttribute("message_login", "用户名或密码不正确");  
 //           return new ResponseEntity<Result>(new Result("6","用户名或密码不正确"), HttpStatus.OK);
        }  
        return null;
    }

	public SysUserBiz getSysUserBiz() {
		return sysUserBiz;
	}

	public void setSysUserBiz(SysUserBiz sysUserBiz) {
		this.sysUserBiz = sysUserBiz;
	}

	public SysRoleBiz getSysRoleBiz() {
		return sysRoleBiz;
	}

	public void setSysRoleBiz(SysRoleBiz sysRoleBiz) {
		this.sysRoleBiz = sysRoleBiz;
	}

	public SysTokenBiz getSysTokenBiz() {
		return sysTokenBiz;
	}

	public void setSysTokenBiz(SysTokenBiz sysTokenBiz) {
		this.sysTokenBiz = sysTokenBiz;
	}


}
